﻿using HidApi;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MySoftLab.DapFlashCore.Probes.DapAccess.Interfaces
{
    public class HidApiUSB : DapInterface
    {
        public const int HIDAPI_MAX_PACKET_COUNT = 30;
        public const string CmsisDapFeatureStr = "CMSIS-DAP";

        private readonly MyDevice _device;
        private uint _vid;
        private uint _pid;
        private string _vendorName;
        private string _productName;
        private string _serialNumber;
        private Dictionary<string, object> _deviceInfo;
        private bool _closed = true;
        private int _packetCount = 0;

        public override uint Vid => _vid;

        public override uint Pid => _pid;

        public override string VendorName => _vendorName;

        public override string ProductName => _productName;

        public override string SerialNumber => _serialNumber;

        public HidApiUSB(MyDevice dev, Dictionary<string, object> info)
        {
            _device = dev;
            _vid = (ushort)info["vendor_id"];
            _pid = (ushort)info["product_id"];
            _vendorName = info.TryGetValue("manufacturer_string", out object? manufactStr) ? (string)manufactStr : _vid.ToString("X");
            _productName = info.TryGetValue("product_string", out object? prodStr) ? (string)prodStr : _pid.ToString("X");
            _serialNumber = info.TryGetValue("serial_number", out object? serialNum) ? (string)serialNum : $"{_vid}-{_pid}-{info["path"]}";
            _deviceInfo = info;
            _closed = true;
        }

        public override void Close()
        {
            _closed = true;
            _device.Dispose();
        }

        public override void Open()
        {
            try
            {
                _device.OpenPath();
                _closed = false;
            }
            catch (Exception ex)
            {
                throw new Exception($"打开设备失败：{ex.Message}");
            }
        }

        public override byte[] Read()
        {
            return _device.Read(PacketSize);
        }

        public override uint ReadSwo()
        {
            return 0;
        }

        private void PrintData(byte[] data)
        {
            Console.Write("dev write:");
            foreach (byte b in data)
            {
                Console.Write(b.ToString("x2"));
            }
            Console.WriteLine();
        }

        public override void Write(byte[] data)
        {
            byte[] bytes = new byte[PacketSize + 1];

            Buffer.BlockCopy(data, 0, bytes, 1, data.Length);

            // PrintData(bytes);

            _device.Write(bytes);
        }

        public static HidApiUSB[] GetAllConnectedInterfaces()
        {
            List<HidApiUSB> boards = [];

            foreach (var deviceInfo in Hid.Enumerate())
            {
                using var device = deviceInfo.ConnectToDevice();
                var info = device.GetDeviceInfo();
                var vid = info.VendorId;
                var pid = info.ProductId;

                if (!deviceInfo.ProductString.Contains(CmsisDapFeatureStr) && !HidHelper.IsKnownCmsisDapVidPid(vid, pid))
                {
                    if (!deviceInfo.Path.Contains(CmsisDapFeatureStr))
                    {
                        continue;
                    }
                }

                if (HidHelper.FilterDeviceByUsagePage(vid, pid, deviceInfo.UsagePage))
                {
                    continue;
                }

                var convDeviceInfo = new Dictionary<string, object>
                {
                    { "vendor_id", vid },
                    { "product_id", pid },
                    { "manufacturer_string", info.ManufacturerString },
                    { "product_string", info.ProductString },
                    { "serial_number", info.SerialNumber }
                };

                var myDevice = new MyDevice(vid, pid, info.Path, deviceInfo.SerialNumber);

                boards.Add(new HidApiUSB(myDevice, convDeviceInfo));
            }

            return [.. boards];
        }
    }
}
